

/*-----------------------------------------------------------------------------
 * HEADER FILES
 *---------------------------------------------------------------------------*/
#include "gmi_time.h"

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __GMI_STM32__
#include "main.h"
#endif

/*-----------------------------------------------------------------------------
 * FUNCTIONS DEFINITION
 *---------------------------------------------------------------------------*/
#if defined(x86_64) || defined(arm64e)
__weak gmi_time_t* gmi_time_init()
{
    gmi_time_t* handle      = malloc(sizeof(gmi_time_t));
    handle->tz.tz_minuteswest = 0;
    handle->tz.tz_dsttime     = 8;

    gettimeofday(&(handle->tv), &(handle->tz));

    handle->timestamp_start = handle->tv.tv_sec * 1000000 + handle->tv.tv_usec;

    return handle;
}

__weak GMI_STATUS gmi_time_deinit(gmi_time_t* handle)
{
    CHECK_HANDLE(handle);
    free(handle);
    return GMI_STATUS_OK;
}


__weak GMI_STATUS gmi_get_real_timestamp(gmi_time_t* handle)
{
    char* tmp       = NULL;
    int format_size = 24;
    struct tm* p;

    CHECK_HANDLE(handle);
    tmp = malloc(23 * sizeof(char));
    time(&(handle->real_time));
    p = gmtime(&(handle->real_time));

#ifdef __clang__
    snprintf(tmp,
             format_size,
             "%d-%d-%d %d:%d:%d.%d",
             1900 + p->tm_year,
             1 + p->tm_mon,
             p->tm_mday,
             8 + p->tm_hour,
             p->tm_min,
             p->tm_sec,
             handle->tv.tv_usec % 1000);
#elif defined __GNUC__
    snprintf(tmp,
             format_size,
             "%d-%d-%d %d:%d:%d.%ld",
             1900 + p->tm_year,
             1 + p->tm_mon,
             p->tm_mday,
             8 + p->tm_hour,
             p->tm_min,
             p->tm_sec,
             handle->tv.tv_usec % 1000);
#endif
    strncpy(handle->str_real_time, tmp, format_size);

    free(tmp);

    return GMI_STATUS_OK;
}


__weak GMI_STATUS gmi_get_tick(gmi_time_t* handle, gmi_ts_us_t* timestamp)
{
    CHECK_HANDLE(handle);
    gmi_ts_us_t tmp = 0;

    gettimeofday(&(handle->tv), &(handle->tz));
    tmp        = handle->tv.tv_sec * 1000000 + handle->tv.tv_usec;
    *timestamp = tmp - handle->timestamp_start;

    return GMI_STATUS_OK;
}

__weak GMI_STATUS gmi_sleep_us(gmi_time_t* handle, gmi_ts_us_t time_to_sleep)
{
    CHECK_HANDLE(handle);

    gmi_ts_us_t ts_tmp    = 0;
    gmi_ts_us_t ts_start  = 0;
    gmi_ts_us_t ts_target = 0;

    gmi_get_tick(handle, &ts_start);
    ts_target = ts_start + time_to_sleep;

    do
    {
        gmi_get_tick(handle, &ts_tmp);
    } while (ts_tmp < ts_target);

    return GMI_STATUS_OK;
}

__weak GMI_STATUS gmi_sleep_ms(gmi_time_t* handle, gmi_ts_ms_t time_to_sleep)
{
    CHECK_HANDLE(handle);

    gmi_ts_us_t ts_tmp    = 0;
    gmi_ts_us_t ts_start  = 0;
    gmi_ts_us_t ts_target = 0;

    gmi_get_tick(handle, &ts_start);
    ts_target = ts_start + time_to_sleep * 1000;

    do
    {
        gmi_get_tick(handle, &ts_tmp);
    } while (ts_tmp < ts_target);

    return GMI_STATUS_OK;
}

__weak GMI_STATUS gmi_sleep_s(gmi_time_t* handle, gmi_ts_s_t time_to_sleep)
{
    CHECK_HANDLE(handle);

    sleep((unsigned int)time_to_sleep);

    return GMI_STATUS_OK;
}

#elif defined(__GMI_STM32__)
__weak GMI_STATUS gmi_get_tick(gmi_time_t* handle, gmi_ts_us_t* timestamp)
{
    *timestamp = HAL_GetTick();

    return GMI_STATUS_OK;
}

__weak GMI_STATUS gmi_sleep_ms(gmi_time_t* handle, gmi_ts_ms_t time_to_sleep)
{
    if(time_to_sleep > 4294967296)
    {
        return GMI_STATUS_PARAM_INVALID;
    }

    HAL_Delay((uint32_t)time_to_sleep);

    return GMI_STATUS_OK;
}

#endif
